import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.LinkedList;
import java.util.Queue;


public class client {

		
		//much the same as last time
		
		//extra things to add:
		//may issue 
		//CHECK, REGISTER, SEARCH, EXT-SEARCH, INVALIDATE and BYE messages
			//i think SEARCH, EXT-SEARCH and INVALIDATE are new
		//shall provide reasonable output to standard out to detail
		//what it is doing and the messages it receives
		
		//When standard input is closed , it should terminate connections
			//what does standard input closing mean?
		
		
	
    public static BufferedReader stdIn = new BufferedReader(
            new InputStreamReader(System.in));
    public static Queue<String> scriptLines =new LinkedList<String>();
    public static String scriptFile = null;
    
    public static void main(String[] args) throws IOException {

        Socket echoSocket = null;
        PrintWriter outToServer = null;

        BufferedReader inFromServer = null;
        
        String serverAddress = null;
        String portString = null;
        
        int port = 0;
        
        if(args.length < 2)
        {
        	System.err.println("ERROR: Must call with command line arguments as follows:");
        	System.err.println("  java client [server-address] [server-port] {[script-file]}");
        	System.exit(1);
        }
        
		//arg 0: server-address test
        serverAddress = args[0];
        //arg 1: server-port
        portString = args[1];
        port = Integer.parseInt(portString);
        
        if(args.length >= 3)
        {
        	scriptFile = args[2];
        	FileReader inFile = null;
        	try{
        		inFile = new FileReader (scriptFile); //open file
        	}
        	catch (FileNotFoundException e) {
        		System.err.println("Error: Could not find the file " + scriptFile);
        		System.err.println("  in directory: " + System.getProperty("user.dir"));
        		System.exit(1);
        	}
    		BufferedReader in = new BufferedReader (inFile); //open reader
    		String line = null;
    		while(in.ready())
    		{
    			line = in.readLine();
    			if(!line.startsWith("%"))
    				scriptLines.add(line.split("%")[0].trim());
    		}
    		in.close();
    		inFile.close();
        }
        
        try {
            echoSocket = new Socket(serverAddress, port);
            outToServer = new PrintWriter(echoSocket.getOutputStream(), true);
            inFromServer = new BufferedReader(new InputStreamReader(
                                        echoSocket.getInputStream()));
        } catch (UnknownHostException e) {
            System.err.println("Don't know about host: " + serverAddress + ".");
            System.exit(1);
        } catch (IOException e) {
            System.err.println("Couldn't get I/O for "
                               + "the connection to: " + serverAddress + ".");
            System.exit(1);
        }
    
        System.out.println("Connected to server " + serverAddress + " on port " + port
        					+ ". (type \"end\" to close connection and exit client)");


		String userInput, responseFromServer;
		
		if(scriptFile == null)
			System.out.print("client: ");
	
		while ((userInput = getNextLine()) != null) {
			if(userInput.equalsIgnoreCase("end"))
			{
				outToServer.println("bye 0x01 0");
				responseFromServer = inFromServer.readLine();
			    System.out.println("server: " + responseFromServer);
				break;
			}
		    outToServer.println(userInput);
		    responseFromServer = inFromServer.readLine();
		    String[] fields = Helpers.extractFields(userInput, " ");
		    String[] responseFields = Helpers.extractFields(responseFromServer, " ");
		    if(userInput.toUpperCase().startsWith("SEARCH "))
		    {
		    	System.out.println(" server: " + responseFromServer);
		    	if(!responseFromServer.toLowerCase().startsWith("error"))
		    	{
		    		
		    		String parameter = fields[Helpers.SEARCH_PARAMETER];
					String justKeywords = parameter.split("%")[0];
					String[] keyWordSets = Helpers.extractFields(justKeywords, "&");
					for(int set = 0; set<keyWordSets.length; set++)
					{
						
						while(!responseFromServer.toLowerCase().startsWith("tx-end"))
						{
							String keyword = null;
							String host;
							String hostport;
							
							if(responseFromServer.toLowerCase().startsWith("redirect"))
							{
								keyword = Helpers.extractFields(responseFromServer, " ")[Helpers.REDIRECT_KEYWORD];
								host = Helpers.extractFields(responseFromServer, " ")[Helpers.REDIRECT_HOST];
								hostport = Helpers.extractFields(responseFromServer, " ")[Helpers.REDIRECT_PORT];
								
								System.out.println("  Information for keyword \"" + keyword + 
										"\" can be found @ " + host + ":" + hostport + ".");
							}
							else if(responseFromServer.toLowerCase().startsWith("search-response"))
							{
								keyword = Helpers.extractFields(responseFromServer, " ")[Helpers.SEARCHRESPONSE_KEYWORD];
								String name = Helpers.extractFields(responseFromServer, " ")[Helpers.SEARCHRESPONSE_NAME];
								System.out.println("  Information for keyword \"" + keyword + 
										"\" was found @ this server (" + name + ").");
								String details = Helpers.arrayToDelimitedList(Helpers.extractFields(responseFromServer, " ", Helpers.SEARCHRESPONSE_DETAILS)," ");
								System.out.println("    Details: " + details);
							}
							responseFromServer = inFromServer.readLine();
							System.out.println(" server: " + responseFromServer);
						}
						System.out.println(" Finished search for keyword set " + keyWordSets[set]);
						if(set == keyWordSets.length-1)
							break;
						responseFromServer = inFromServer.readLine();
					}
					System.out.println(" Finished search for all keyword sets in parameter: " + parameter);
		    		
		    	}
		    }
		    else if(userInput.toUpperCase().startsWith("EXT-SEARCH "))
		    {
		    	System.out.println(" server: " + responseFromServer);
		    	if(!responseFromServer.toLowerCase().startsWith("error"))
		    	{
		    		String parameter = fields[Helpers.EXTSEARCH_PARAMETER];
					String justKeywords = parameter.split("%")[0];
					String[] keyWordSets = Helpers.extractFields(justKeywords, "&");
					for(int set = 0; set<keyWordSets.length; set++)
					{
						while(!responseFromServer.toLowerCase().startsWith("tx-end"))
						{
							String keyword = null;
							
							if(responseFromServer.toLowerCase().startsWith("ext-search-invalid"))
							{
								keyword = Helpers.extractFields(responseFromServer, " ")[Helpers.EXTSEARCHINVALID_KEYWORD];
								
								System.out.println("  Information for keyword \"" + keyword + 
										"\" can not be found @ this host.");
							}
							else if(responseFromServer.toLowerCase().startsWith("ext-search-response"))
							{
								keyword = Helpers.extractFields(responseFromServer, " ")[Helpers.EXTSEARCHRESPONSE_KEYWORD];
								String name = Helpers.extractFields(responseFromServer, " ")[Helpers.EXTSEARCHRESPONSE_NAME];
								System.out.println("  Information for keyword \"" + keyword + 
										"\" was found @ this server (" + name + ").");
								String details = Helpers.arrayToDelimitedList(Helpers.extractFields(responseFromServer, " ", Helpers.EXTSEARCHRESPONSE_DETAILS)," ");
								System.out.println("    Details: " + details);
							}
							responseFromServer = inFromServer.readLine();
							System.out.println(" server: " + responseFromServer);
						}
						System.out.println(" Finished ext-search for keyword set " + keyWordSets[set]);
						if(set == keyWordSets.length-1)
							break;
						responseFromServer = inFromServer.readLine();
					}
					System.out.println(" Finished ext-search for all keyword sets in parameter: " + parameter);
		    		
		    	}
		    }
		    else if(userInput.toUpperCase().startsWith("CHECK "))
		    {
		    	System.out.println(" server: " + responseFromServer);
		    	if(responseFields[Helpers.CHECKRESPONSE_TORF].equals("true"))
		    		System.out.println("  keyword "+fields[Helpers.CHECK_KEYWORD]+" is available.");
		    	else
		    		System.out.println("  keyword "+fields[Helpers.CHECK_KEYWORD]+" is already registered.");
		    }
		    else if(userInput.toUpperCase().startsWith("REGISTER "))
		    {
		    	System.out.println(" server: " + responseFromServer);
		    	if(responseFields[Helpers.REGISTERSTATUS_TORF].equals("true"))
		    		System.out.println("  keyword "+fields[Helpers.REGISTER_KEYWORD]+" registered successfully.");
		    	else
		    		System.out.println("  keyword "+fields[Helpers.REGISTER_KEYWORD]+" is already registered. Did not register.");
		    	
		    }
		    else if(userInput.toUpperCase().startsWith("INVALIDATE "))
		    {
		    	String keyword = Helpers.extractFields(responseFromServer, " ")[Helpers.REDIRECT_KEYWORD];
		    	String host = Helpers.extractFields(responseFromServer, " ")[Helpers.REDIRECT_HOST];
				String hostport = Helpers.extractFields(responseFromServer, " ")[Helpers.REDIRECT_PORT];
				
		    	System.out.println(" server: " + responseFromServer);
		    	System.out.println("  Information for keyword \"" + keyword + 
						"\" can be found @ " + host + ":" + hostport + ".");
		    }
		    else if(userInput.toUpperCase().startsWith("QUERY "))
		    {
		    	String keyword = Helpers.extractFields(userInput, " ")[Helpers.QUERY_KEYWORD];
		    	String numfields = Helpers.extractFields(responseFromServer, " ")[Helpers.QUERYRESPONSE_NUMFIELDS];
		    	System.out.println(" server: " + responseFromServer);
		    	
		    	if(numfields.equals("1"))
		    		System.out.println("  Information for keyword \"" + keyword + 
						"\" was not found. Most likely it is not registered yet.");
		    	else if(numfields.equals("7"))
		    	{
		    		System.out.println("  Information for keyword \"" + keyword + 
					"\" was found.");
			    	String details = Helpers.arrayToDelimitedList(Helpers.extractFields(responseFromServer, " ", Helpers.QUERYRESPONSE_DETAILS)," ");
					System.out.println("    Details: " + details);
		    	}
	    	
		    }
		    else
		    {
			    System.out.println("server: " + responseFromServer);
			    if (responseFromServer.toLowerCase().startsWith("bye"))
		            break;
			 
		    }
		       if(scriptFile == null)
					System.out.print("client: ");
		}
		
		
	
		outToServer.close();
		inFromServer.close();
		stdIn.close();
		echoSocket.close();
		
		System.out.println("Disconnected from server.");
	
    }
    
	public static String getNextLine()
	{
		String nextLine = null;
		if(scriptFile != null)
		{
			nextLine = scriptLines.remove();
			System.out.println("client: " + nextLine);
		} else
			try {
				nextLine = stdIn.readLine();
			} catch (IOException e) {
				e.printStackTrace();
			}
		return nextLine;
	}

}
